package boundary;

import java.awt.Cursor;
import java.awt.Font;
import java.awt.GridBagLayout;
import javax.swing.JPanel;
import javax.swing.JLabel;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Date;
import java.util.Set;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JComboBox;
import javax.swing.JButton;
import javax.swing.SwingConstants;
import store.BaseStore;
import store.Menu;
import store.Termine;
import store.Terminologia;
import dataview.Data;
import dataview.Difficolta;
import dataview.InfoCibo;
import dataview.InfoMenu;
import dataview.Termini;
import dataview.TipoTermine;
import exceptions.DBException;
import java.awt.Insets;
import javax.swing.JScrollPane;
import org.jdesktop.swingx.JXDatePicker;
import javax.swing.BorderFactory;
import javax.swing.border.BevelBorder;
import java.awt.Dimension;

public class ModificaInfoMenu extends JPanel implements ActionListener {
	
	private static final long serialVersionUID = 1L;
	private Home home;
	private Menu vecchioMenu;
	private Set<String> tagStagionalita; //  @jve:decl-index=0:
	private Set<String> tagOccasione;
	private JLabel jLabel = null;
	private JLabel jLabel1 = null;
	private JLabel jLabel2 = null;
	private JLabel jLabel3 = null;
	private JTextField tfPersone = null;
	private JLabel jLabel4 = null;
	private JLabel jLabel5 = null;
	private JButton bCrea = null;
	private String nomeMenu;
	private JScrollPane spPres = null;
	private JTextArea taPres = null;
	private JScrollPane spNote = null;
	private JTextArea jTextArea1 = null;
	private JXDatePicker JXDatePicker = null;
	private JComboBox cbStagionalita = null;
	private JLabel lStagionalita = null;
	private JLabel lOccasione = null;
	private JComboBox cbOccasione = null;
	private Star stars[] = new Star[3];
	private JPanel starsPanel;
	
	private JButton modificheInfo = null;
	
	/**
	 * This is the default constructor
	 */
	public ModificaInfoMenu(Home home, Menu menu) {
		super();
		this.home = home;
		this.vecchioMenu = menu;
		this.nomeMenu = menu.getNome();
		initialize();
	}
	
	/**
	 * This method initializes this
	 * 
	 * @return void
	 */
	private void initialize() {
		GridBagConstraints gridBagConstraints13 = new GridBagConstraints();
		gridBagConstraints13.gridx = 1;
		gridBagConstraints13.insets = new Insets(3, 3, 3, 3);
		gridBagConstraints13.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints13.gridy = 7;
		GridBagConstraints gridBagConstraints20 = new GridBagConstraints();
		gridBagConstraints20.fill = GridBagConstraints.BOTH;
		gridBagConstraints20.gridy = 2;
		gridBagConstraints20.weightx = 1.0;
		gridBagConstraints20.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints20.anchor = GridBagConstraints.WEST;
		gridBagConstraints20.gridx = 1;
		GridBagConstraints gridBagConstraints19 = new GridBagConstraints();
		gridBagConstraints19.fill = GridBagConstraints.BOTH;
		gridBagConstraints19.gridy = 1;
		gridBagConstraints19.weightx = 1.0;
		gridBagConstraints19.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints19.anchor = GridBagConstraints.WEST;
		gridBagConstraints19.gridx = 1;
		GridBagConstraints gridBagConstraints18 = new GridBagConstraints();
		gridBagConstraints18.fill = GridBagConstraints.VERTICAL;
		gridBagConstraints18.gridy = 2;
		gridBagConstraints18.weightx = 1.0;
		gridBagConstraints18.insets = new Insets(0, 3, 0, 0);
		gridBagConstraints18.anchor = GridBagConstraints.WEST;
		gridBagConstraints18.gridx = 1;
		GridBagConstraints gridBagConstraints17 = new GridBagConstraints();
		gridBagConstraints17.gridx = 0;
		gridBagConstraints17.anchor = GridBagConstraints.CENTER;
		gridBagConstraints17.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints17.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints17.gridy = 2;
		lOccasione = new JLabel();
		lOccasione.setText("Occasione");
		lOccasione.setFont(new Font("Dialog", Font.BOLD, 12));
		GridBagConstraints gridBagConstraints16 = new GridBagConstraints();
		gridBagConstraints16.gridx = 0;
		gridBagConstraints16.anchor = GridBagConstraints.CENTER;
		gridBagConstraints16.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints16.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints16.gridy = 1;
		lStagionalita = new JLabel();
		lStagionalita.setText("Stagionalita'");
		lStagionalita.setFont(new Font("Dialog", Font.BOLD, 12));
		GridBagConstraints gridBagConstraints15 = new GridBagConstraints();
		gridBagConstraints15.fill = GridBagConstraints.VERTICAL;
		gridBagConstraints15.gridy = 1;
		gridBagConstraints15.weightx = 1.0;
		gridBagConstraints15.anchor = GridBagConstraints.WEST;
		gridBagConstraints15.insets = new Insets(0, 3, 0, 0);
		gridBagConstraints15.gridx = 1;
		GridBagConstraints gridBagConstraints31 = new GridBagConstraints();
		gridBagConstraints31.gridx = 1;
		gridBagConstraints31.anchor = GridBagConstraints.WEST;
		gridBagConstraints31.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints31.fill = GridBagConstraints.NONE;
		gridBagConstraints31.gridy = 6;
		GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
		gridBagConstraints2.fill = GridBagConstraints.BOTH;
		gridBagConstraints2.gridy = 4;
		gridBagConstraints2.weightx = 1.0;
		gridBagConstraints2.weighty = 1.0;
		gridBagConstraints2.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints2.gridx = 1;
		GridBagConstraints gridBagConstraints12 = new GridBagConstraints();
		gridBagConstraints12.fill = GridBagConstraints.BOTH;
		gridBagConstraints12.gridy = 3;
		gridBagConstraints12.weightx = 1.0;
		gridBagConstraints12.weighty = 1.0;
		gridBagConstraints12.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints12.gridx = 1;
		GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
		gridBagConstraints11.gridx = 0;
		gridBagConstraints11.gridwidth = 2;
		gridBagConstraints11.fill = GridBagConstraints.NONE;
		gridBagConstraints11.insets = new Insets(10, 5, 10, 5);
		gridBagConstraints11.gridy = 8;
		GridBagConstraints gridBagConstraints10 = new GridBagConstraints();
		gridBagConstraints10.fill = GridBagConstraints.VERTICAL;
		gridBagConstraints10.gridy = 7;
		gridBagConstraints10.weightx = 1.0;
		gridBagConstraints10.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints10.anchor = GridBagConstraints.WEST;
		gridBagConstraints10.gridx = 1;
		GridBagConstraints gridBagConstraints9 = new GridBagConstraints();
		gridBagConstraints9.gridx = 0;
		gridBagConstraints9.anchor = GridBagConstraints.WEST;
		gridBagConstraints9.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints9.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints9.gridy = 7;
		jLabel5 = new JLabel();
		jLabel5.setText("Difficolta'");
		jLabel5.setFont(new Font("Dialog", Font.BOLD, 12));
		GridBagConstraints gridBagConstraints7 = new GridBagConstraints();
		gridBagConstraints7.gridx = 0;
		gridBagConstraints7.anchor = GridBagConstraints.CENTER;
		gridBagConstraints7.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints7.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints7.gridy = 6;
		jLabel4 = new JLabel();
		jLabel4.setText("Data menu");
		jLabel4.setFont(new Font("Dialog", Font.BOLD, 12));
		GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
		gridBagConstraints6.fill = GridBagConstraints.BOTH;
		gridBagConstraints6.gridy = 5;
		gridBagConstraints6.weightx = 1.0;
		gridBagConstraints6.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints6.anchor = GridBagConstraints.WEST;
		gridBagConstraints6.gridx = 1;
		GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
		gridBagConstraints5.gridx = 0;
		gridBagConstraints5.anchor = GridBagConstraints.WEST;
		gridBagConstraints5.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints5.gridy = 5;
		jLabel3 = new JLabel();
		jLabel3.setText("Numero persone *");
		jLabel3.setFont(new Font("Dialog", Font.BOLD, 12));
		GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
		gridBagConstraints3.gridx = 0;
		gridBagConstraints3.anchor = GridBagConstraints.NORTHWEST;
		gridBagConstraints3.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints3.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints3.gridy = 4;
		jLabel2 = new JLabel();
		jLabel2.setText("Note");
		jLabel2.setFont(new Font("Dialog", Font.BOLD, 12));
		GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
		gridBagConstraints1.gridx = 0;
		gridBagConstraints1.anchor = GridBagConstraints.NORTHWEST;
		gridBagConstraints1.insets = new Insets(5, 5, 5, 5);
		gridBagConstraints1.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints1.gridy = 3;
		jLabel1 = new JLabel();
		jLabel1.setText("Presentazione *");
		jLabel1.setFont(new Font("Dialog", Font.BOLD, 12));
		GridBagConstraints gridBagConstraints = new GridBagConstraints();
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridwidth = 3;
		gridBagConstraints.gridy = 0;
		jLabel = new JLabel();
		jLabel.setText(nomeMenu);
		jLabel.setFont(new Font("Dialog", Font.BOLD, 22));
		this.setSize(345, 335);
		this.setLayout(new GridBagLayout());
		this.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
		this.add(jLabel, gridBagConstraints);
		this.add(jLabel1, gridBagConstraints1);
		this.add(jLabel2, gridBagConstraints3);
		this.add(jLabel3, gridBagConstraints5);
		this.add(getTfPersone(), gridBagConstraints6);
		this.add(jLabel4, gridBagConstraints7);
		this.add(jLabel5, gridBagConstraints9);
		this.add(getBCrea(), gridBagConstraints11);
		this.add(getSpPres(), gridBagConstraints12);
		this.add(getSpNote(), gridBagConstraints2);
		this.add(getJXDatePicker(), gridBagConstraints31);
		this.add(lStagionalita, gridBagConstraints16);
		this.add(lOccasione, gridBagConstraints17);
		this.add(getCbStagionalita(), gridBagConstraints19);
		this.add(getCbOccasione(), gridBagConstraints20);
		this.add(getStarsPanel(), gridBagConstraints13);
		
		if (vecchioMenu.getInfo() != null) {
			GridBagConstraints gbc = new GridBagConstraints();
			gbc.gridx = 0;
			gbc.fill = GridBagConstraints.NONE;
			gbc.gridwidth = 3;
			gbc.anchor = GridBagConstraints.CENTER;
			gbc.insets = new Insets(5, 5, 5, 5);
			gbc.gridy = 11;
			this.add(getSalvaModificheInfo(), gbc);
		}
	}
	
	/**
	 * This method initializes jTextField
	 * 
	 * @return javax.swing.JTextField
	 */
	private JTextField getTfPersone() {
		if (tfPersone == null) {
			tfPersone = new JTextField();
			tfPersone.setColumns(20);
			tfPersone.addKeyListener(new NumericAdapter());
			if (vecchioMenu.getInfo() != null) {
				tfPersone.setText(String.valueOf(vecchioMenu.getInfo().getNumeroPersone()));
			}
		}
		return tfPersone;
	}
	
	/**
	 * This method initializes jButton
	 * 
	 * @return javax.swing.JButton
	 */
	private JButton getBCrea() {
		if (bCrea == null) {
			bCrea = new JButton();
			bCrea.setText(vecchioMenu.getInfo() == null ? "Inserisci Portate" : "Modifica Portate");
			bCrea.setCursor(new Cursor(Cursor.HAND_CURSOR));
			bCrea.setHorizontalTextPosition(SwingConstants.TRAILING);
			bCrea.setIcon(new ImageIcon(getClass().getResource("/icone/accept-icon.png")));
			bCrea.setFont(new Font("Dialog", Font.BOLD, 12));
			bCrea.addActionListener(this);
		}
		return bCrea;
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == bCrea || e.getSource() == modificheInfo) {
			do {
				String pres = taPres.getText();
				if (pres == null || pres.length() < 200) {
					JOptionPane.showMessageDialog(this, "Inserire una presentazione di almeno 200 caratteri per il menu", "Errore", JOptionPane.ERROR_MESSAGE);
					break;
				}
				String pers = tfPersone.getText();
				if (pers.length() < 1 || Integer.parseInt(pers) < 1 || pers.length() > 5) {
					JOptionPane.showMessageDialog(this, "Inserire il numero di persone per cui e` pensato il menu", "Errore", JOptionPane.ERROR_MESSAGE);
					break;
				}
				Date d = getJXDatePicker().getDate();
				Data data = d == null ? null : new Data(d);
				Termini tag = new Termini();
				if (cbOccasione.getSelectedIndex() != 0) tag.add(new Termine(TipoTermine.tipo_occasione, cbOccasione.getSelectedItem().toString()));
				if (cbStagionalita.getSelectedIndex() != 0) tag.add(new Termine(TipoTermine.stagionalita, cbStagionalita.getSelectedItem().toString()));
				vecchioMenu.modifica(new InfoMenu(data, pres, getJTextArea1().getText(), Integer.parseInt(pers), getDifficolta()), tag);
				if (e.getSource() == bCrea) {
					home.visualizzaPortate(vecchioMenu);
				} else {
					try {
						if (BaseStore.salvaModifiche(vecchioMenu))
							JOptionPane.showMessageDialog(this, "Menu modificato correttamente", "Menu modificato", JOptionPane.INFORMATION_MESSAGE);
					} catch (Exception exc) {
						exc.printStackTrace();
						JOptionPane.showMessageDialog(this, "Menu non modificato a causa di un errore", "Errore", JOptionPane.ERROR_MESSAGE);
					}
					home.mostraListaMenu(null);
				}
			} while (false);
		}
	}
	
	/**
	 * This method initializes spPres
	 * 
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getSpPres() {
		if (spPres == null) {
			spPres = new JScrollPane();
			spPres.setViewportView(getTaPres());
		}
		return spPres;
	}
	
	/**
	 * This method initializes jTextArea
	 * 
	 * @return javax.swing.JTextArea
	 */
	private JTextArea getTaPres() {
		if (taPres == null) {
			taPres = new JTextArea();
			taPres.setWrapStyleWord(true);
			taPres.setLineWrap(true);
			taPres.setFont(new Font("Dialog", Font.PLAIN, 12));
			taPres.setTabSize(0);
			if (vecchioMenu.getInfo() != null) {
				taPres.setText(vecchioMenu.getInfo().getPresentazione());
				taPres.addKeyListener(new java.awt.event.KeyAdapter() {
					public void keyPressed(java.awt.event.KeyEvent e) {
						if (e.getKeyCode() == KeyEvent.VK_TAB) {
							if (e.isShiftDown())
								getCbOccasione().requestFocus();
							else getJTextArea1().requestFocus();
						}
					}
				});
			}
		}
		return taPres;
	}
	
	/**
	 * This method initializes spNote
	 * 
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getSpNote() {
		if (spNote == null) {
			spNote = new JScrollPane();
			spNote.setViewportView(getJTextArea1());
		}
		return spNote;
	}
	
	/**
	 * This method initializes jTextArea1
	 * 
	 * @return javax.swing.JTextArea
	 */
	private JTextArea getJTextArea1() {
		if (jTextArea1 == null) {
			jTextArea1 = new JTextArea();
			jTextArea1.setWrapStyleWord(true);
			jTextArea1.setLineWrap(true);
			jTextArea1.setTabSize(0);
			jTextArea1.setFont(new Font("Dialog", Font.PLAIN, 12));
			if (vecchioMenu.getInfo() != null) {
				jTextArea1.setText(vecchioMenu.getInfo().getNote());
				jTextArea1.addKeyListener(new java.awt.event.KeyAdapter() {
					public void keyPressed(java.awt.event.KeyEvent e) {
						if (e.getKeyCode() == KeyEvent.VK_TAB) {
							if (e.isShiftDown())
								getTaPres().requestFocus();
							else getTfPersone().requestFocus();
						}
					}
				});
			}
		}
		return jTextArea1;
	}
	
	/**
	 * This method initializes JXDatePicker
	 * 
	 * @return org.jdesktop.swingx.JXDatePicker
	 */
	private JXDatePicker getJXDatePicker() {
		if (JXDatePicker == null) {
			JXDatePicker = new JXDatePicker();
			JXDatePicker.setEditable(true);
			if (vecchioMenu.getInfo() != null && vecchioMenu.getInfo().getQuando() != null) JXDatePicker.setDate(vecchioMenu.getInfo().getQuando().getTime());
		}
		return JXDatePicker;
	}
	
	/**
	 * This method initializes cbStagionalita
	 * 
	 * @return javax.swing.JComboBox
	 */
	private JComboBox getCbStagionalita() {
		if (cbStagionalita == null) {
			try {
				tagStagionalita = Terminologia.getTerminologia().getTuttiTermini(TipoTermine.stagionalita);
				tagStagionalita.add("Seleziona stagionalita'..");
				cbStagionalita = new JComboBox(tagStagionalita.toArray());
				cbStagionalita.setFont(new Font("Dialog", Font.PLAIN, 12));
				if (vecchioMenu.getTag() != null && !vecchioMenu.getTag().getTerminiDiTipo(TipoTermine.stagionalita).isEmpty())
					cbStagionalita.setSelectedItem(vecchioMenu.getTag().getTerminiDiTipo(TipoTermine.stagionalita).getFirst().toString());
			} catch (DBException e) {
				e.printStackTrace();
			}
		}
		return cbStagionalita;
	}
	
	/**
	 * This method initializes cbOccasione
	 * 
	 * @return javax.swing.JComboBox
	 */
	private JComboBox getCbOccasione() {
		if (cbOccasione == null) {
			try {
				tagOccasione = Terminologia.getTerminologia().getTuttiTermini(TipoTermine.tipo_occasione);
				tagOccasione.add("Seleziona occasione..");
				cbOccasione = new JComboBox(tagOccasione.toArray());
				cbOccasione.setFont(new Font("Dialog", Font.PLAIN, 12));
				if (vecchioMenu.getTag() != null && !vecchioMenu.getTag().getTerminiDiTipo(TipoTermine.tipo_occasione).isEmpty())
					cbOccasione.setSelectedItem(vecchioMenu.getTag().getTerminiDiTipo(TipoTermine.tipo_occasione).getFirst().toString());
			} catch (DBException e) {
				e.printStackTrace();
			}
		}
		return cbOccasione;
	}
	
	/**
	 * This method initializes starsPanel
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getStarsPanel() {
		if (starsPanel == null) {
			starsPanel = new JPanel();
			
			starsPanel.setLayout(new GridBagLayout());
			for (int i = 0; i < stars.length; i++) {
				GridBagConstraints gbc = new GridBagConstraints();
				gbc.gridx = i;
				gbc.gridy = 0;
				gbc.insets = new Insets(2, 2, 2, 2);
				stars[i] = new Star();
				stars[i].setToolTipText(Difficolta.values()[i].toString());
				starsPanel.add(stars[i], gbc);
			}
			
			if (vecchioMenu.getInfo() != null && vecchioMenu.getInfo().getDifficolta() != null)
				stars[vecchioMenu.getInfo().getDifficolta().ordinal()].setAttivato(true);
			
		}
		return starsPanel;
	}
	
	private int ultimoAttivato() {
		for (int i = stars.length - 1; i >= 0; i--)
			if (stars[i].isAttivato()) return i;
		return -1;
	}
	
	private Difficolta getDifficolta() {
		int i = ultimoAttivato();
		if (i != -1) return Difficolta.values()[i];
		return null;
	}
	
	private class Star extends JLabel {
		private boolean attivato = false;
		private final Icon ATTIVATO_ICON = new ImageIcon(getClass().getResource("/icone/gold-star.gif"));
		private final Icon DISATTIVATO_ICON = new ImageIcon(getClass().getResource("/icone/silver-star.gif"));
		private final Icon HOVER_ICON = new ImageIcon(getClass().getResource("/icone/platinum-star.gif"));
		private final Icon ATTIVATO_HOVER_ICON = new ImageIcon(getClass().getResource("/icone/bronze-star.gif"));
		
		Star() {
			super();
			
			setIcon(DISATTIVATO_ICON);
			setCursor(new Cursor(Cursor.HAND_CURSOR));
			addMouseListener(new MouseAdapter() {
				public void mousePressed(MouseEvent e) {
					int i = indexOf();
					if (attivato && i != ultimoAttivato())
						stars[i + 1].setAttivato(!getAttivato());
					else setAttivato(!getAttivato());
				}
				
				public void mouseEntered(MouseEvent e) {
					if (!attivato) {
						for (int i = 0; i <= indexOf(); i++)
							stars[i].setIcon(ATTIVATO_ICON);
					} else setIcon(ATTIVATO_HOVER_ICON);
				}
				
				public void mouseExited(MouseEvent e) {
					if (!attivato)
						for (int i = 0; i <= indexOf(); i++)
							if (stars[i].isAttivato())
								stars[i].setIcon(ATTIVATO_ICON);
							else stars[i].setIcon(DISATTIVATO_ICON);
					else setIcon(ATTIVATO_ICON);
				}
			});
		}
		
		boolean isAttivato() {
			return attivato;
		}
		
		void setAttivato(boolean b) {
			if (attivato != b) {
				attivato = b;
				int i = indexOf();
				if (attivato) {
					setIcon(ATTIVATO_ICON);
					if (indexOf() > 0) stars[i - 1].setAttivato(attivato);
				} else {
					setIcon(DISATTIVATO_ICON);
					if (indexOf() < stars.length - 1) stars[i + 1].setAttivato(attivato);
				}
			}
		}
		
		public boolean getAttivato() {
			return attivato;
		}
		
		private int indexOf() {
			for (int i = 0; i < stars.length; i++)
				if (this == stars[i]) return i;
			return -1;
		}
	}
	
	/**
	 * This method initializes modificheInfo
	 * 
	 * @return javax.swing.JButton
	 */
	private JButton getSalvaModificheInfo() {
		if (modificheInfo == null) {
			modificheInfo = new JButton();
			modificheInfo.setVisible(true);
			modificheInfo.setText("Salva le modifiche alle informazioni");
			modificheInfo.setIcon(new ImageIcon(getClass().getResource("/icone/accept-icon.png")));
			modificheInfo.setFont(new Font("Dialog", Font.BOLD, 12));
			modificheInfo.addActionListener(this);
		}
		return modificheInfo;
	}
	
} //  @jve:decl-index=0:visual-constraint="0,0"
